<template>
	<div
		:class="[
			'app-editor-container',
			'app-mob-cascader',
			`app-mob-cascader-${name}`,
			`app-mob-cascader--${editorStyle}`,
		]"
	>
		<van-field
			readonly
			v-model="textValue"
			:disabled="disabled"
			:autosize="true"
			:type="multiple ? 'textarea' : 'text'"
			:placeholder="placeholder"
			@click="setPopupState(true)"
		>
			<template #right-icon>
				<van-icon v-if="textValue" name="clear" @click="handleClear" />
				<van-icon name="arrow-down" />
			</template>
		</van-field>
		<van-popup
			round
			teleport="body"
			position="bottom"
			v-model:show="popupState"
			class="cascader__popup"
		>
			<div class="popup__container">
				<div class="popup__header">
					<div @click="cancel" class="cancel">
						{{ $t('common.generic.onCancel', '取消') }}
					</div>
					<div @click="confirm" class="confirm">
						{{ $t('common.generic.okText', '确定') }}
					</div>
				</div>
                <div class="popup__content">
                    <AppMobTree
                        v-bind="$attrs"
                        :fieldNames="fieldNames"
                        :multiple="multiple"
                        :items="treeData"
                        :load="cascaderLoadData"
                        :selectedKeys="selectedKeys"
                        @selectionChange="handleSelectChange"
                    />
                </div>
			</div>
		</van-popup>
	</div>
</template>
<script setup lang="ts">
import {
	deepCopy,
	IEntityDetail,
	IEvent,
	IParam,
	typeOf,
	createUUID,
} from '@/core';
import { isFunc } from 'qx-util';
import { Ref } from 'vue';
import { CascaderProps, ValueItemType } from './cascader';
import { useEditorTypeParams } from '@/hooks/use-editor';
const props = defineProps(CascaderProps);
interface EditorEmit {
	(name: 'editor-event', value: IEvent<string>): void;
}
// 类型校验
const { validateConfig } = useEditorTypeParams();
validateConfig();
const emit = defineEmits<EditorEmit>();
/**
 * 模态状态
 */
const popupState = ref(false);
/**
 * 树数据
 */
const treeData: Ref<IParam[]> = ref([]);
/**
 * 级联选择器数据集
 */
const items: any[] = [];
/**
 * 选中数据keys
 */
const selectedKeys: Ref<string[]> = ref([]);
/**
 * 值项数据
 */
let valueItemData: any[] = [];
/**
 * 当前数据
 */
let curSelectText: string[] = [];
/**
 * 树节点配置
 */
const fieldNames: IParam = {
	text: 'label',
	value: 'nodeId',
	children: 'children',
	leaf: 'isLeaf',
};
/**
 * 设置模态状态
 */
const setPopupState = (state: boolean) => {
	popupState.value = state;
};
watch(
	() => props.value,
	(newVal: any, oldVal: any) => {
		initSelectData();
	}
);
/**
 * @description 初始化数据
 */
const initData = () => {
	loadData(props.valueItems[0]).then((_treeData: IParam[]) => {
		if (_treeData) {
			if (treeData.value.length > 0) {
				_treeData.forEach((node: IParam) => {
					const index = treeData.value.findIndex(
						(_node: any) => node.value == _node.value
					);
					if (index > -1) {
						Object.assign(treeData.value[index], node);
					} else {
						treeData.value.push(node);
					}
				});
			} else {
				treeData.value = _treeData;
			}
		}
	});
};
/**
 * 显示文本
 */
const textValue = computed(() => {
	let value: string = '';
	try {
		if (props.value) {
			const values: string[] = JSON.parse(props.value);
			value = `${values.join('\n')}`;
		}
	} catch (error) {
		console.error(error);
	}
	return value;
});
/**
 * @description 获取树数据
 * @param nodes  树数据
 * @param parentKey 父数据
 * @param childNodes 子节点数据集合
 */
const getTreeData = (
	nodes: IParam[],
	parentKey: string,
	childNodes: IParam[]
) => {
	if (nodes && nodes.length > 0) {
		nodes.forEach((node: any) => {
			if (node.value == parentKey) {
				childNodes = node.children || [];
			} else {
				getTreeData(node.children, parentKey, childNodes);
			}
		});
	} else {
		childNodes = [];
	}
};

/**
 * @description 设置树数据
 * @param treeData 树数据
 * @param treePath 树路径
 * @param index 树层级索引
 */
const setTreeData = (
	treeData: IParam[],
	treePath: string[],
	index: number,
	parent?: any
) => {
	if (index > -1 && index < treePath.length) {
		const item = items.find((item: IParam) => item.value == treePath[index]);
		const treeItem = treeData.find(
			(item: IParam) => item.value == treePath[index]
		);
		if (!treeItem) {
			const children: IParam = {
				label: item.label,
				value: item.value,
				plabel: index ? [...parent.plabel, parent.label] : [],
				pvalue: index ? [...parent.pvalue, parent.value] : [],
				isLeaf: index == treePath.length - 1,
				nodeId: `${parent ? parent.value + '_' + item.value : item.value}`,
				index,
			};
            if (!children.isLeaf) {
                children.children = [];
			    setTreeData(children.children, treePath, index + 1, children);
            }
			treeData.push(children);
		} else {
            if (!treeItem.isLeaf) {
                if (!treeItem.children) {
                    treeItem.children = [];
                }
                setTreeData(treeItem.children, treePath, index + 1, treeItem);
            }
		}
	}
};
/**
 * @description 初始化选中数据
 */
const initSelectData = () => {
	if (props.value && props.valueItems.length > 0) {
		const values: string[] = JSON.parse(props.value);
		const selectData: IParam[] = [];
		const valueItemData: IParam[] = [];
		props.valueItems.forEach((valueItem: any) => {
			valueItemData.push({
				name: valueItem.name,
				value: props.data[valueItem.name]
					? props.data[valueItem.name].split(',')
					: [],
			});
		});
		values.forEach((label: string, index: number) => {
			const value: string[] = [];
			valueItemData.forEach((item: IParam) => {
				value.push(item.value[index]);
			});
			selectData.push({ label, value: value.join(props.separator) });
		});
		selectData.forEach((select: IParam) => {
			const _values: any[] = select.value.split(props.separator);
			const _labels: any[] = select.label.split(props.separator);
			_values.forEach((value: string, index: number) => {
				const item = items.find((item: any) => item.value == value);
				if (!item) {
					items.push({ value, label: _labels[index] });
				}
			});
		});
		let tempSelectValue: any[] = [];
		let tempTreeSelectValue: any[] = [];
		selectData.forEach((select: IParam) => {
			tempSelectValue.push(select.value.split(props.separator));
		});
		tempSelectValue.forEach((select: string[]) => {
			setTreeData(treeData.value, select, 0);
			tempTreeSelectValue.push(
				select[select.length - 2] + '_' + select[select.length - 1]
			);
		});
		selectedKeys.value = tempTreeSelectValue;
	}
};
/**
 * @description 处理选中值改变
 * @param selected 选中数据
 */
const handleSelectChange = (selected: IParam[]) => {
    valueItemData = [];
    curSelectText = [];
	props.valueItems.forEach((valueItem: any) => {
		valueItemData.push({ name: valueItem.name, value: [] });
	});
	if (selected && selected.length > 0) {
		selected.forEach((item: IParam) => {
			const { value, label, pvalue, plabel } = item;
			const values: string[] = [...pvalue, value];
			const labels: string[] = [...plabel, label];
			valueItemData.forEach((valueItem: IParam, index: number) => {
				valueItem.value.push(values[index]);
			});
			curSelectText.push(labels.join(props.separator));
		});
	}
};
/**
 * @description 处理选中数据
 */
const handleSelectData = () => {
    valueItemData.forEach((valueItem: any) => {
		doEditorEmit({
			name: valueItem.name,
			action: 'valueChange',
			data: valueItem.value.length > 0 ? valueItem.value.join(',') : null,
		});
	});
	doEditorEmit({
		name: props.name,
		action: 'valueChange',
		data: curSelectText.length > 0 ? JSON.stringify(curSelectText) : null,
	});
}
/**
 * @description 处理加载数据（去重）
 * @param data 加载数据
 * @param pvalue 父节点主键
 */
const handleLoadData = (data: IParam[], pvalue: string): IParam[] => {
	const tempData: IParam[] = [];
	getTreeData(treeData.value, pvalue, tempData);
	data.forEach((item: IParam) => {
		const _index = tempData.findIndex(
			(_item: any) => item.value == _item.value
		);
		if (_index > 0) {
			Object.assign(tempData[_index], item);
		} else {
			tempData.push(item);
		}
	});
	return tempData;
};
/**
 * @description 级联选择器加载数据
 * @param selectedOptions 选中节点配置
 */
const cascaderLoadData = async (selectedOptions: any) => {
	const { index, value, pvalue, plabel, label } = selectedOptions;
	const _pvalue = [...pvalue, value];
	const _plabel = [...plabel, label];
	const data: IParam[] = await loadData(
		props.valueItems[index + 1],
		index + 1,
		_pvalue,
		_plabel
	);
	const tempData: IParam[] = handleLoadData(data, value);
	selectedOptions.children = tempData;
	// 设置节点加载状态，避免重复加载
	selectedOptions.isLoaded = true;
	treeData.value = [...treeData.value];
};
/**
 * @description 处理请求参数
 * @param index 树层级索引
 * @param pvalue 父数据值
 */
const handleQueryParams = (index: number, pvalue: string[]) => {
	const context = deepCopy(props.context);
	const viewParams = deepCopy(props.viewParams);
	const entityDetails = App.getAppEntityConfig();
	if (index > 0 && pvalue.length > 0) {
		const pValueItem: ValueItemType = props.valueItems[index - 1];
		const pDataEntity: IEntityDetail | undefined = entityDetails.find(
			(detail: IEntityDetail) => {
				return detail.codeName == pValueItem.appDataEntity;
			}
		);
		if (pDataEntity) {
			Object.assign(context, {
				[pDataEntity.codeName.toLowerCase()]: pvalue[pvalue.length - 1],
			});
			Object.assign(viewParams, {
				[`n_${pDataEntity.keyField.toLowerCase()}_eq`]:
					pvalue[pvalue.length - 1],
			});
		}
	}
	return { context, viewParams };
};
/**
 * @description 加载数据
 * @param valueItem 值项
 * @param index 树层级索引
 * @param pvalue 父数据值集合
 */
const loadData = async (
	valueItem: ValueItemType,
	index: number = 0,
	pvalue: string[] = [],
	plabel: string[] = []
): Promise<IParam[]> => {
	const entityDetails = App.getAppEntityConfig();
	let data: IParam[] = [];
	const valueItemDataEntity: IEntityDetail | undefined = entityDetails.find(
		(detail: IEntityDetail) => {
			return detail.codeName == valueItem.appDataEntity;
		}
	);
	// 未配置属性关联实体 和 数据集
	if (!valueItemDataEntity || !valueItem.dataSet) {
		return data;
	}
	const service = await App.getDataService(
		valueItem.appDataEntity,
		props.context
	);
	// 关联实体服务不存在 不加载数据
	if (!service || isFunc(service[valueItem.dataSet])) {
		return data;
	}
	const { context, viewParams } = handleQueryParams(index, pvalue);
	const response = await service[valueItem.dataSet](context, viewParams);
	if (response.success) {
		data = response.data.map((item: any) => {
			const value = item[valueItemDataEntity.keyField.toLowerCase()];
			const label = item[valueItemDataEntity.majorField.toLowerCase()];
			return {
				value,
				label,
				plabel,
				pvalue,
				isLeaf: index == props.valueItems.length - 1,
				nodeId: `${
					pvalue.length > 0 ? pvalue[pvalue.length - 1] + '_' + value : value
				}`,
				index,
			};
		});
		data.forEach((node: any) => {
			const index = items.findIndex((item: any) => node.value == item.value);
			if (index != -1) {
				items[index] = node;
			} else {
				items.push(node);
			}
		});
	}
	return data;
};
/**
 * @description 清空
 * @param event 事件源
 */
const handleClear = (event: MouseEvent) => {
	event.stopPropagation();
	event.preventDefault();
	selectedKeys.value = [];
	props.valueItems.forEach((valueItem: any) => {
		doEditorEmit({
			name: valueItem.name,
			action: 'valueChange',
			data: null,
		});
	});
	doEditorEmit({
		name: props.name as string,
		action: 'valueChange',
		data: null,
	});
};
/**
 * @description 取消
 */
const cancel = () => {
	initSelectData();
	setPopupState(false);
};
/**
 * @description 确定
 */
const confirm = () => {
	handleSelectData();
	setPopupState(false);
};
/**
 * @description 编辑器事件抛出
 */
const doEditorEmit = (value: IEvent<string>) => {
	emit('editor-event', value);
};
onBeforeMount(() => {
	initData();
});
</script>
